////////////////////////////////////////////////
// DESCRIPTION:
//     Classes for accessing Device memory and I/O windows
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//
#pragma once

#include <auto_xxx.hxx>

namespace FusionWare
{
    namespace DFX
    {
        class DeviceWindow
        {
        public:           
            DeviceWindow();
            DeviceWindow(const DeviceWindow& Src);
            DeviceWindow( const ParentBusDriver& BusDriver
                        , const PHYSICAL_ADDRESS& PhysAddress
                        , BOOL InIoSpaceVal
                        , UINT32 WindowSizeVal
                        , UINT32 StrideVal
                        );

            ~DeviceWindow();

            DeviceWindow& operator=(const DeviceWindow& Src);

            // provides 2 stage construction for arrays where default
            // constructor MUST be used
            //
            void Init( const ParentBusDriver& BusDriver
                     , const PHYSICAL_ADDRESS& PhysAddress
                     , BOOL InIoSpaceVal
                     , UINT32 WindowSizeVal
                     , UINT32 StrideVal
                     );

            ///////////////////////////////////////////////////////
            // Description: 
            //    Allocates virtual space for the window and
            //    calculates register addresses based on stride
            //
            // Input: 
            //    RegOffsets[] - Array of register offets assuming byte alignment
            //    NumRegisters - Number of registers in RegOffset and pRegisters
            //
            // Output:
            //    pRegisters[] - Array of register pointers adjusted for Stride 
            //
            // Remarks: 
            //    This method is used to allocate the virtual address for the
            //    device window and to compute register locations based on Stride.
            //    This is used for all off chip peripherals and any on-chip ones
            //    that have register sets matching standard off chip parts.
            //    (E.g. On chip 16550 style UART)
            //
            // Note: 
            //     This function is Idempotent. The virtual mapping
            //     occurs only once.
            //
            bool AllocDeviceRegs(const UINT32 RegOffsets[], size_t NumRegisters, void* pRegisters[]);

            ///////////////////////////////////////////////////////
            // Description: 
            //     Maps the Windows physical address to virtual
            //
            // Remarks: 
            //     Uses information provided in constructor to
            //     map a physical address window into virtual space
            //     
            // Note: 
            //     This function is Idempotent. The virtual mapping
            //     occurs only once.
            //
            bool AllocDeviceRegs();

            ///////////////////////////////////////////////////////
            // Description: 
            //     Releases the virtual mapping from AllocDeviceRegs()
            //
            // Remarks: 
            //     This is safe to call for all addresses as this
            //     class keeps track of whether the window is in 
            //     I/O space or Memory mapped and only releases the
            //     memory mapped addresses.
            // 
            void FreeDeviceRegs();

            UINT32 GetSize()       { return this->WindowSize; }
            void* GetVirtualBase() { return this->pVirtBase; }
            UINT32 GetStride()     { return this->Stride; }
            
            void GetBase(PHYSICAL_ADDRESS* pBase)
            {
                ASSERT(pBase!=NULL);
                *pBase = this->PhysAddr;
            }
            
            bool IsResourceAvailable();

        protected:
            PHYSICAL_ADDRESS PhysAddr;
            UINT32 WindowSize;
            UINT32 Stride;
            ULONG InIoSpace;
            ParentBusDriver Bus;
            void* pVirtBase;
        };

        class DeviceWindows 
        {
        public:
            DeviceWindows()
                : NumMemWindows(0)
                , NumIoWindows(0)
            {
            }

            ~DeviceWindows()
            {
            }

            // Load information about the windows from the registry.
            //
            bool LoadFromRegistry( FusionWare::Win32::RegKey& Key
                                 , const ParentBusDriver& ParentBus
                                 );
    
            // For each memory or I/O window translate it's physical address
            // to a virtual one
            bool TransAddresses();

            ce::auto_array_ptr<DeviceWindow> IoWindows;
            ce::auto_array_ptr<DeviceWindow> MemoryWindows;

            DWORD GetNumIoWindows()  { return this->NumIoWindows; }
            DWORD GetNumMemWindows() { return this->NumMemWindows; }

        protected:
            DWORD NumIoWindows;
            DWORD NumMemWindows;
            bool LoadOneWindowFromReg( FusionWare::Win32::RegKey& Key
                                     , const ParentBusDriver& ParentBus
                                     , ce::auto_array_ptr<DeviceWindow>& pMemInfo
                                     , const TCHAR* pBaseLen
                                     , const TCHAR* pLenName
                                     , const TCHAR* pStrideName
                                     , bool InIoSpace
                                     , DWORD* pNumWindows
                                     );
        };
    }
}